# http://apis.juhe.cn/simpleWeather/query
# 10977a6f668f302326641ef40234ff88
import json
import sys
import requests
import uuid
from functools import reduce
from pathlib import Path
sys_path = str(Path(__file__).resolve().parent.parent)
sys.path.append(sys_path)
from ai_configs import defalut_ai_config
from main import ai_chat_history

MAX_LEN = 5
histories = []

# /*---------------------------------------定义工具类-------------------------------------------*/
class AgentTool:
  def __init__(self,name,description,invoke):
    self.name = name
    self.description = description
    self.invoke = invoke
  
# /*---------------------------------------实例大模型架构工具类-------------------------------------------*/
def architect_invoke():
  with open("./data/architect.json","r",encoding="utf-8") as file:
    content = file.read()
    return content
  
architect_tool = AgentTool(
  name="architect",
  description="查询大模型架构",
  invoke=architect_invoke
)

# /*---------------------------------------实例大模型历史工具类-------------------------------------------*/
def history_invoke():
  with open("./data/history.json","r",encoding="utf-8") as file:
    content = file.read()
    return content
  
history_tool = AgentTool(
  name="history",
  description="查询大模型历史",
  invoke=history_invoke
)

# /*---------------------------------------查询天气实例-------------------------------------------*/
def weather_invoke(params):
  city = None

  if "city" in params:
    params = json.loads(params)
    # print(params,11111)
    city = params["city"]
    # print(city,2222222)
  if city == None:
    print("查询失败，没有输入要查询城市，请输入要查询天气的城市")
    return None
  
  response = requests.get("http://v.juhe.cn/weather/index",params={
    "key":"10977a6f668f302326641ef40234ff88",
    "cityname":city
  })
  temp = response.json()["result"]["today"]
  weather_data = f"city，气温：{temp["temperature"]}，天气：{temp["weather"]}，风向：{temp["wind"]}"
  return weather_data

weather_tool = AgentTool(
  name="weather",
  description="""查询某个城市的天气，需要参数，参数格式为"{"city":""}"，其中city属性为用户要查询的城市，请把用户输入的城市名赋值给city属性 """,
  invoke=weather_invoke
)

# /*---------------------------------------创建查询、插入、删除的待办事项实例-------------------------------------------*/
TODOS_PATH = "./data/todos.json"
def get_todos():
  with open(TODOS_PATH,"r",encoding="utf-8") as file:
    content = file.read()
    if content is None or content == "":
      return []
    content = json.loads(content)
    return content

def save_todos(new_todos):
    if new_todos is None or new_todos == "":
      new_todos = []
    with open(TODOS_PATH,"w",encoding="utf-8") as file:
      file.write(json.dumps(new_todos,ensure_ascii=False))

def query_todo_invoke():
  todos = get_todos()
  all_text = ''
  for item in todos:
    all_text += f" {item["content"]}"
  # return f"待办事项有：{all_text}"
  return json.dumps(todos,ensure_ascii=False)

query_todo_tool = AgentTool(
  name="query_todo",
  description="查询所有的待办事项工具",
  invoke=query_todo_invoke
)

def add_todo_invoke(params):
  content = None
  if "content" in params:
    params = json.loads(params)
    # print(params,11111)
    content = params["content"]
    # print(city,2222222)
  if content is None or content == "":
    print("添加待办事项失败，待办事项内容为空，请输入待办事项内容")
    return "添加待办事项失败"
  new_todo = {"id":str(uuid.uuid4()),"content":content}
  todos = get_todos()
  todos.append(new_todo)
  save_todos(todos)
  return f"已添加待办事项：{content}"

add_todo_tool = AgentTool(
  name="add_todo",
  description="""添加待办事项工具，此工具需要参数，参数格式为"{"content":""}"的json，把用户输入的新增待办事项内容赋值给参数content属性""",
  invoke=add_todo_invoke
)

def delete_todo_invoke(params):
  params = json.loads(params)
  if "all" in params:
    if params["all"] == True:
      save_todos([])
      return "已删除所有待办"
  if "ids" in params:
    todos = get_todos()
    delete_text = ''
    keep_todos = []

    for item in todos:
      if not (item["id"] in params["ids"]):
        keep_todos.append(item)
        delete_text += f" {item["content"]}"
        save_todos(keep_todos)
        
    return f"已删除{delete_text}事项"

delete_todo_tool = AgentTool(
  name="delete_todo",
  description="""
  删除待办事项工具，此工具需要参数，参数格式为"{"ids":[],"all":False}"的json，
  在调用该工具前需要先调用查询待办事项工具拿到待办事项列表，
  根据用户的输入确定要删除的事项，
  用要删除事项的内容逐一去匹配待办事项列表中事项的内容，
  如能匹配上把待办事项列表中匹配上的待办事项的id属性添加进参数ids列表属性中，
  如用户要删除所有待办事项，
  把参数all属性设置为True
  """,
  invoke=delete_todo_invoke
)

# /*---------------------------------------定义Agent类-------------------------------------------*/
class Agent():
  def __init__(self,name,description):
    self.name = name
    self.description = description
    self.tools = []
    self.agents = []
  
  def add_tool(self,tool):
    self.tools.append(tool)

  def add_agent(self,agent):
    self.agents.append(agent)

  def get_agent_prompt(self):
    TOOL_PROMPT = reduce(lambda x,y:x+f"  {y.name}\n  工具作用：{y.description}\n",self.tools,"")
    AGENT_PROMPT = reduce(lambda x,y:x+f"  {y.name}\n  智能体的职责：{y.description}\n",self.agents,"")
    SYS_PROMPT = '''
      你是一名工具、智能体调用专家，需要根据用户的提问找出需要调用的工具返回给用户，
      返回的格式为一个json，json格式为{result_params}，你要把找到的工具名赋值给tool属性，
      有些工具需要参数，根据工具提示把对应用户传入信息赋值给工具参数，并把工具参数赋值给params属性，
      如果没有对应工具就是查找智能体列表中的其他智能体，如果用户的要求符合智能体列表中某一智能体的功能则返回这个智能体，
      同样返回一个json，json格式为{result_params}，把这个智能体的名字赋值给tool属性，
      并把用户的输入一字不改作为参数赋值给params属性

      工具列表清单：
      {tools_params}

      智能体列表清单：
      {agents_params}
      '''.format(
        result_params="""{"tool":"","params":""}""",
        tools_params=TOOL_PROMPT,
        agents_params=AGENT_PROMPT
      )
    return SYS_PROMPT

  def invoke_histories(self,user_content):
    histories.append({
      "role":"user",
      "content":user_content
    })
    current_histories = histories[-1*MAX_LEN:]
    current_histories.insert(0,{
      "role":"system",
      "content":self.get_agent_prompt()
    })
    try:
      tool_agent_info = ai_chat_history(current_histories,defalut_ai_config["doubao"])
      print(tool_agent_info,"tool_info 1")
      tool_agent_info = json.loads(tool_agent_info)
      tool_data = None
      for tool in self.tools:
        if tool.name == tool_agent_info["tool"]:
          if tool_agent_info["params"] != "":
            tool_data = tool.invoke(tool_agent_info["params"])
          else:
            tool_data = tool.invoke()
      for agent in self.agents:
        if agent.name == tool_agent_info["tool"]:
          agent.invoke_histories(tool_agent_info["params"])

      print(tool_data,"tool_data")
      histories.append({
        "role":"assistant",
        "content":tool_data
      })
      current_histories = histories[-1*MAX_LEN:]
      current_histories.insert(0,{
        "role":"system",
        "content":"""
        针对用户对于待办事项的操作，严格按照待办事项的提示操作，不允许把待办工具的返回做任何修改，直接返回给用户，
        非待办事项操作，你需要根据工具的返回结果和用户的提问，整理成通俗易懂的文本来回答用户
        """
      })
      tool_info = ai_chat_history(current_histories,defalut_ai_config["doubao"])
      print(tool_info,"tool_info 2")
      histories.append({
      "role":"assistant",
        "content":tool_info
      })
    except Exception as e:
      print(f"发生错误，具体信息如下：{e}")

# /*---------------------------------------主逻辑-------------------------------------------*/
def get_user_content():
  user_content = input("你好，请输入你的问题：")
  return user_content

global_user_content = get_user_content()

tool_agent = Agent("tool_agent","待办事项智能体，负责待办事项的查询、添加、删除")
tool_agent.add_tool(query_todo_tool)
tool_agent.add_tool(add_todo_tool)
tool_agent.add_tool(delete_todo_tool)

main_agent = Agent("main","入口智能体")
main_agent.add_tool(architect_tool)
main_agent.add_tool(history_tool)
main_agent.add_tool(weather_tool)
main_agent.add_agent(tool_agent)

while global_user_content!="exit":
  main_agent.invoke_histories(global_user_content)
  global_user_content = get_user_content()
